#include <iostream>
#include <fstream>
#include <io.h>

#define MAKE_TYPE_COUNT      1
#define MAKE_TYPE_DATA      2


using namespace std;

ofstream outBinFile;
ofstream outHeadfile;

uint32_t dataOffsetAddr ;
uint32_t infoOffsetAddr ;
uint32_t fileCount ;

int findFilesAndMake(const char *dir,char makeType);
int wavToPCMData(const string filePath,char makeType);
int stringToUpper(string& str);

int main(int argc, char const *argv[])
{
    if(argc < 2)
    {
        fprintf(stderr,"commond error");
        return -1;
    }
    const char *pDir = argv[1];
    string strName ;
    string strNameUpper ;
    string strSearchDir ;
    string strOutDir ;
    strSearchDir = argv[1];
    strName = strSearchDir.substr(strSearchDir.rfind("\\")+1);
    strOutDir = strSearchDir.substr(0,strSearchDir.rfind("\\")+1);
    strNameUpper = strName;
    stringToUpper(strNameUpper);

    outBinFile.open(strOutDir + "drumSound_" + strName + ".bin",ios::binary | ios::out);
    if(!outBinFile)
    {
        fprintf(stderr,"error-create out file fail\n");
        return -1;
    }
    outHeadfile.open(strOutDir + "drumSound_" + strName + ".h",ios::binary | ios::out);
    if(!outHeadfile)
    {
        fprintf(stderr,"error-open head file fail\n");
    }

    fprintf(stdout,"search file ...\n");
	fileCount = 0 ;
	findFilesAndMake(pDir,MAKE_TYPE_COUNT);
    fprintf(stdout,"search ok.\ntotal file %ld\n",static_cast<unsigned long>(fileCount));

    string strArrayDefine = "#ifndef __DRUM_SOUND_" + strNameUpper + "_H\r\n";
    strArrayDefine += "#define __DRUM_SOUND_" + strNameUpper + "_H\r\n\r\n#include \"drumSoundStruct.h\"\r\n";
    outHeadfile.write(strArrayDefine.c_str(),strArrayDefine.length());
    string strMaxDefine = "DRUM_SOUND_" + strNameUpper + "_MAX";
    strArrayDefine = "\r\n#define " + strMaxDefine + "\t" + to_string(fileCount) + "\r\n" ;
    outHeadfile.write(strArrayDefine.c_str(),strArrayDefine.length());
    strArrayDefine = "\r\nMEM_ASSIGN_DRUM_SOUND_STRUCT(const __DRUM_SOUND_INFO drumSoundInfo_" + strName + "[" + strMaxDefine + "])=\r\n{\r\n";
    outHeadfile.write(strArrayDefine.c_str(),strArrayDefine.length());

	outBinFile.write(reinterpret_cast<char *>(&fileCount),4);
	infoOffsetAddr  = 8;
    dataOffsetAddr  = infoOffsetAddr + (fileCount * 8);
    dataOffsetAddr += 512 - (dataOffsetAddr % 512) ;

    fprintf(stdout,"make file ...\n");
	fileCount = 0 ;
    findFilesAndMake(pDir,MAKE_TYPE_DATA);
    fprintf(stdout,"make done!\n");
    strArrayDefine = "};\r\n\r\n#endif\r\n";
    outHeadfile.write(strArrayDefine.c_str(),strArrayDefine.length());
    outBinFile.close();
    outHeadfile.close();
    return 0;
}



int findFilesAndMake(const char *dir,char makeType)
{
    char path[512];
    intptr_t handle;
    struct _finddata_t fileInfo ;

    strcpy(path,dir);
    strcat(path,"/*.*");
    handle = _findfirst(path,&fileInfo);
    if(handle == -1)
    {
        fprintf(stderr,"error-find first file\n") ;
        return -1;
    }
    do
    {
        if(fileInfo.attrib & _A_SUBDIR)
        {
            if((strcmp(fileInfo.name,".") == 0) || (strcmp(fileInfo.name,"..") == 0))
            {
                continue;
            }
            fprintf(stdout,"<sub dir>\t%s\n",fileInfo.name);
            strcpy(path,dir);
            strcat(path,"\\");
            strcat(path,fileInfo.name);
            findFilesAndMake(path,makeType);
        }
        else
        {
            strcpy(path,dir);
            strcat(path,"\\");
            strcat(path,fileInfo.name);
            wavToPCMData(path,makeType);
        }
    } while (!_findnext(handle,&fileInfo));
    _findclose(handle);
    return 0;
}


#define AUDIO_CHANNEL           1
#define AUDIO_RATE              44100
#define AUDIO_SAMPLEBYTE        2
#define AUDIO_DATABIT           16

int wavToPCMData(const string filePath,char makeType)
{
	uint32_t curPoint,ChunkID,ChunkSize,Format,SampleRate,ByteRate;
	uint16_t PCMFormat,NumChannels,BlockAlign,BitsPerSample;

    ifstream wavFile(filePath,ios::binary | ios::in);
    if(!wavFile)
    {
        fprintf(stderr,"error-open %s error",filePath.c_str());
        return -1;
    }

	wavFile.read(reinterpret_cast<char *>(&ChunkID),4) ;
	if ( ChunkID != 0x46464952 )
	{
        wavFile.close() ;
		return 0 ;
	}
	wavFile.read((char *)&ChunkSize,4) ;//ChunkSize应该等于文件总长度减8
	wavFile.read((char *)&Format,4) ;
	if ( Format != 0x45564157 )//"WAVE"
	{
		wavFile.close() ;
		return 0 ;
	}

	while(1)
	{
		wavFile.read((char *)&ChunkID,4) ;
		wavFile.read((char *)&ChunkSize,4) ;
        if(wavFile.eof())
		{
			wavFile.close() ;
			return 0 ;
		}
		if ( ChunkID == 0x20746D66 )	//"fmt "
		{
			curPoint = wavFile.tellg();
			wavFile.read((char *)&PCMFormat,2) ;
			wavFile.read((char *)&NumChannels,2) ;
			wavFile.read((char *)&SampleRate,4) ;
			wavFile.read((char *)&ByteRate,4) ;
			wavFile.read((char *)&BlockAlign,2) ;
			wavFile.read((char *)&BitsPerSample,2) ;
//			if ( PCMFormat != 0x0001 )
//			{
//				wavFile.close() ;
//				return 0 ;
//			}
			if ( NumChannels != AUDIO_CHANNEL )
			{
				wavFile.close() ;
				return 0 ;
			}
			if ( SampleRate != AUDIO_RATE )
			{
				wavFile.close() ;
				return 0 ;
			}
			if ( ByteRate != (SampleRate * AUDIO_SAMPLEBYTE))
			{
				wavFile.close() ;
				return 0 ;
			}
//			if ( BlockAlign != AUDIO_SAMPLEBYTE)
//			{
//				wavFile.close() ;
//				return 0 ;
//			}
			if ( BitsPerSample != AUDIO_DATABIT )
			{
				wavFile.close() ;
				return 0 ;
			}
            wavFile.seekg(curPoint + ChunkSize);
		}
		else if ( ChunkID == 0x61746164 ) //data
		{
            fileCount++;
            if( makeType == MAKE_TYPE_DATA)
            {
                fprintf(stdout,"make file: %s\n",filePath.c_str());
                string strKey,strDepth;
                size_t n;
                size_t i;
                n = filePath.rfind(".");
                i = filePath.rfind("_");
                strDepth = filePath.substr(i+1,n-i-1);
                n = i ;
                i = filePath.rfind("_",i-1);
                strKey = filePath.substr(i+1,n-i-1);
                i = 0 ;
                while(strDepth[i] == '0')
                {
                    strDepth.replace(i,1," ");
                    i++;
                }
                i = 0 ;
                while(strKey[i] == '0')
                {
                    strKey.replace(i,1," ");
                    i++;
                }
                string strHead = "\t{" + strKey + "," + strDepth + "},\r\n";
                outHeadfile.write(strHead.c_str(),strHead.length());

                char *pData = (char *)malloc(ChunkSize);
                if(pData == 0)
                {
                    return -2;
                }
                uint32_t sector = dataOffsetAddr / 512;
				outBinFile.seekp(infoOffsetAddr);
                outBinFile.write(reinterpret_cast<char *>(&sector),4);
                outBinFile.write(reinterpret_cast<char *>(&ChunkSize),4);
				outBinFile.seekp(dataOffsetAddr);
                wavFile.read(pData,ChunkSize);
                outBinFile.write(pData,ChunkSize);
                free(pData);
				infoOffsetAddr += 8;
				dataOffsetAddr += ChunkSize;
				if((dataOffsetAddr % 512) > 0)
				{
					dataOffsetAddr += 512 - (dataOffsetAddr % 512) ;
				}
            }
			else if(makeType == MAKE_TYPE_COUNT)
            {
            }
			break ;
		}
		else
		{
			curPoint = wavFile.tellg();
			wavFile.seekg(curPoint + ChunkSize);
		}
	}
    wavFile.close() ;
    return 0;
}


int stringToUpper(string& str)
{
    size_t l = str.length();
    for(size_t n=0; n<l; n++)
    {
        if((str[n] >= 'a') && (str[n] <= 'z'))
        {
            str[n] -= 32;
        }
    }
    return 0;
}
